package ltd.sshine.tracking.web.advice;



import io.opentelemetry.api.trace.Span;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import jakarta.validation.Path;
import lombok.extern.slf4j.Slf4j;
import ltd.sshine.runtime.exception.ServiceException;
import ltd.sshine.runtime.exception.SystemException;
import ltd.sshine.runtime.exception.SystemRuntimeException;
import ltd.sshine.runtime.pojo.Result;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.validation.method.ParameterValidationResult;
import org.springframework.web.ErrorResponse;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.HandlerMethodValidationException;
import org.springframework.web.multipart.MultipartException;

import java.io.IOException;
import java.util.Optional;

@RestControllerAdvice
@Slf4j
public class ExceptionControllerAdvice {
    /**
     * 服务异常处理
     */
    @ExceptionHandler({ServiceException.class})
    @ResponseStatus(HttpStatus.OK)
    public Result<Object> customExceptionHandler(ServiceException e) {
        return Result.error(e.getMsg(), e.getCode());
    }

    /**
     * 系统服务运行异常
     */
    @ExceptionHandler({SystemRuntimeException.class})
    @ResponseStatus(HttpStatus.OK)
    public Result<Object> systemRuntimeException(SystemRuntimeException e) {
        log.error(e.getThrowable().getMessage());
        return Result.error(e.getMsg(), e.getCode());
    }

    /**
     * 参数校验异常
     */
    @ExceptionHandler({MethodArgumentNotValidException.class})
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Object> argumentNotValidHandler(MethodArgumentNotValidException e) {
        BindingResult bindingResult = e.getBindingResult();
        String message = null;
        if (bindingResult.hasErrors()) {
            FieldError fieldError = bindingResult.getFieldError();
            if (fieldError != null) {
                message = fieldError.getField() + fieldError.getDefaultMessage();
            } else {
                //如果不是属性错误，则为对象处理错误
                ObjectError objectError = e.getBindingResult().getAllErrors().get(0);
                message = objectError.getDefaultMessage();
            }
        }
        return Result.error(message, HttpStatus.BAD_REQUEST.value());
    }

    /**
     * 校验参数异常
     */
    @ExceptionHandler({ConstraintViolationException.class})
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Object> springArgumentNotValidHandler(ConstraintViolationException e) {
        Optional<ConstraintViolation<?>> first = e.getConstraintViolations().stream().findFirst();
        if (first.isEmpty()) {
            return exceptionHandler(e);
        }
        ConstraintViolation<?> constraintViolation = first.get();
        Path path = constraintViolation.getPropertyPath();
        String s = path.toString();
        String substring = s.substring(s.indexOf('.') + 1);
        return Result.error(substring + ":" + constraintViolation.getMessage());
    }
    @ExceptionHandler({HandlerMethodValidationException.class})
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Object> handlerMethodValidationHandler(HandlerMethodValidationException e) {
        Optional<ParameterValidationResult> first= e.getAllValidationResults().stream().findFirst();
        if (first.isEmpty()) {
            return exceptionHandler(e);
        }
        ParameterValidationResult parameterValidationResult = first.get();
        String parameterName = parameterValidationResult.getMethodParameter().getParameterName();
        String defaultMessage = parameterValidationResult.getResolvableErrors().get(0).getDefaultMessage();
        return Result.error(parameterName + ":" + defaultMessage);
    }


    /**
     * 表单异常
     */
    @ExceptionHandler({MultipartException.class})
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Object> methodNotSupported(MultipartException e) {
        return Result.error("表单异常", HttpStatus.BAD_REQUEST.value());
    }

    /**
     * 无法处理的数据格式
     */
    @ExceptionHandler({HttpMessageNotReadableException.class})
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Object> messageNotReadable(HttpMessageNotReadableException e) {

        return Result.error("无法处理的数据格式", HttpStatus.BAD_REQUEST.value());
    }

    /**
     * 缺少请求参数
     */
    @ExceptionHandler({MissingServletRequestParameterException.class})
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Object> missingServletRequestParameterException(MissingServletRequestParameterException e) {
        return Result.error("缺少请求参数:" + e.getParameterName(), 403);
    }

    /**
     * 未考虑到的异常
     */
    @ExceptionHandler({Exception.class})
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Result<Object> unknownException(Exception e, HttpServletResponse response) {

        if (e instanceof ErrorResponse errorResponse) {
            HttpHeaders headers = errorResponse.getHeaders();
            headers.forEach((name, values) -> {
                values.forEach((value) -> {
                    response.addHeader(name, value);
                });
            });
            int status = errorResponse.getStatusCode().value();
            String message = errorResponse.getBody().getDetail();
            try {
                if (message != null) {
                    response.sendError(status, message);
                } else {
                    response.sendError(status);
                }
            } catch (IOException ex) {
                throw new RuntimeException(ex);
            }
            return null;
        }
        log.error("未知异常", e);
        Span current = Span.current();
        if (current.getSpanContext().isValid()){
            response.setHeader("trace-id",current.getSpanContext().getTraceId());
        }
        return Result.error(SystemException.UNKNOWN_EXCEPTION.getMsg(), SystemException.UNKNOWN_EXCEPTION.getCode());
    }

    /**
     * 未考虑到的异常
     */
    public Result<Object> exceptionHandler(Exception e) {

        log.error("未知异常", e);
        return Result.error(SystemException.UNKNOWN_EXCEPTION.getMsg(), SystemException.UNKNOWN_EXCEPTION.getCode());
    }
}